import uuid
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
from datetime import timedelta

class AccessLog(models.Model):
    """
    Records each access attempt, whether successful or not.
    """
    # Can be null if the person is not recognized
    user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='access_logs')
    device = models.ForeignKey('Device', on_delete=models.SET_NULL, null=True, blank=True, related_name='access_logs', verbose_name="Device")
    timestamp = models.DateTimeField(auto_now_add=True, verbose_name="Timestamp")
    is_success = models.BooleanField(default=False, verbose_name="Access Granted")
    snapshot_path = models.CharField(max_length=255, help_text="Path to the snapshot image taken during the access attempt.")
    failure_reason = models.CharField(max_length=100, blank=True, help_text="Reason for access failure (e.g., unknown_card, face_not_match)")

    class Meta:
        ordering = ['-timestamp']

    def __str__(self):
        status = "Success" if self.is_success else "Failed"
        user_info = self.user.username if self.user else "Unknown"
        device_info = self.device.name if self.device else "Unknown Device"
        return f"{status} access by {user_info} on {device_info} at {self.timestamp.strftime('%Y-%m-%d %H:%M')}"

class Device(models.Model):
    """
    Represents a physical access control device.
    """
    device_id = models.CharField(max_length=100, unique=True, primary_key=True, help_text="Unique identifier for the device (e.g., ESP32_001)")
    name = models.CharField(max_length=100, help_text="Human-readable name for the device")
    location = models.CharField(max_length=255, blank=True, help_text="Physical location of the device")
    camera_service_name = models.CharField(
        max_length=100,
        blank=True,
        help_text="The name of the camera service associated with this device (e.g., 'main_gate_cam'). This name is used as a key in settings.CAMERA_SERVICES."
    )
    status = models.CharField(
        max_length=20,
        choices=[('online', 'Online'), ('offline', 'Offline'), ('error', 'Error')],
        default='offline',
        verbose_name="Device Status"
    )
    ip_address = models.GenericIPAddressField(null=True, blank=True, verbose_name="IP Address")
    firmware_version = models.CharField(max_length=50, blank=True, verbose_name="Firmware Version")
    last_seen = models.DateTimeField(null=True, blank=True, verbose_name="Last Seen")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="Date Added")

    class Meta:
        verbose_name = "Device"
        verbose_name_plural = "Devices"
        ordering = ['-created_at']

    def __str__(self):
        return f"{self.name} ({self.device_id})"

class VideoStreamToken(models.Model):
    """
    A short-lived, single-use token to authorize access to a video stream.
    """
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    user = models.ForeignKey(User, on_delete=models.CASCADE, help_text="The admin user who requested the stream.")
    device = models.ForeignKey(Device, on_delete=models.CASCADE, help_text="The device stream being accessed.")
    created_at = models.DateTimeField(auto_now_add=True)
    is_used = models.BooleanField(default=False)

    def is_valid(self):
        """
        Checks if the token is still valid (not used and not expired).
        Tokens are valid for a short period, e.g., 10 seconds, to prevent reuse.
        """
        if self.is_used:
            return False
        
        # Tokens are valid for 10 seconds
        return timezone.now() < self.created_at + timedelta(seconds=10)

    def __str__(self):
        return f"Token for {self.device.name} requested by {self.user.username}"
